package com.bank;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/**
 * 银行系统命令行界面
 * 提供POSIX风格的命令行操作界面
 */
public class BankSystem {
    private final Map<String, Account> accounts;
    private final Scanner scanner;
    
    public BankSystem() {
        this.accounts = new HashMap<>();
        this.scanner = new Scanner(System.in);
    }
    
    /**
     * 启动银行系统
     */
    public void start() { // 公共方法，启动银行系统的主循环
        System.out.println("=== 欢迎使用银行账户管理系统 ==="); // 打印欢迎信息
        System.out.println("输入 'help' 查看可用命令"); // 打印帮助提示
        System.out.println(); // 打印空行，增加可读性
        
        while (true) { // 无限循环，持续接收用户命令
            System.out.print("bank> "); // 打印命令提示符
            String input = scanner.nextLine().trim(); // 读取用户输入并去除首尾空格
            
            if (input.isEmpty()) { // 检查输入是否为空
                continue; // 如果为空，跳过本次循环继续下一次
            }
            
            try { // 开始try块，处理命令执行中的异常
                if (!processCommand(input)) { // 调用processCommand处理命令，如果返回false则退出
                    break; // exit命令返回false，跳出循环
                }
            } catch (Exception e) { // 捕获命令处理中的异常
                System.err.println("错误: " + e.getMessage()); // 向错误输出流打印错误信息
            }
            System.out.println(); // 打印空行，分隔命令输出
        }
        
        scanner.close(); // 关闭Scanner资源
        System.out.println("感谢使用银行账户管理系统！"); // 打印退出信息
    }
    
    /**
     * 处理命令
     * @param input 用户输入的命令
     * @return true继续运行，false退出系统
     */
    private boolean processCommand(String input) { // 私有方法，处理用户输入的命令
        String[] parts = parseCommand(input); // 调用parseCommand方法解析命令
        if (parts.length == 0) { // 检查解析结果是否为空
            return true; // 如果为空，返回true继续运行
        }
        
        String command = parts[0].toLowerCase(); // 获取命令名并转换为小写
        
        switch (command) { // 根据命令名进行分支处理
            case "create": // 创建账户命令
                handleCreateCommand(parts); // 调用创建账户处理方法
                break; // 跳出switch语句
            case "deposit": // 存款命令
                handleDepositCommand(parts); // 调用存款处理方法
                break; // 跳出switch语句
            case "withdraw": // 取款命令
                handleWithdrawCommand(parts); // 调用取款处理方法
                break; // 跳出switch语句
            case "transfer": // 转账命令
                handleTransferCommand(parts); // 调用转账处理方法
                break; // 跳出switch语句
            case "balance": // 查询余额命令
                handleBalanceCommand(parts); // 调用余额查询处理方法
                break; // 跳出switch语句
            case "help": // 帮助命令
                showHelp(); // 调用显示帮助方法
                break; // 跳出switch语句
            case "exit": // 退出命令
                return false; // 返回false，指示系统应该退出
            default: // 未知命令
                System.err.println("未知命令: " + command + "。输入 'help' 查看可用命令。"); // 打印错误信息
        }
        
        return true; // 返回true，继续运行系统
    }
    
    /**
     * 解析命令行参数
     * @param input 输入字符串
     * @return 解析后的参数数组
     */
    private String[] parseCommand(String input) { // 私有方法，解析命令行输入
        // 简单的空格分割，支持基本的参数解析
        return input.trim().split("\\s+"); // 去除首尾空格后按空白字符分割字符串
    }
    
    /**
     * 处理创建账户命令
     * create -id <账户ID> -name <姓名> -balance <初始余额>
     */
    private void handleCreateCommand(String[] args) { // 私有方法，处理创建账户命令
        try { // 开始try块，捕获可能的异常
            String id = null, name = null; // 声明并初始化账户ID和姓名变量
            double balance = 0.0; // 声明并初始化余额变量
            
            for (int i = 1; i < args.length; i += 2) { // 从索引1开始遍历参数数组，每次增加2（参数名和参数值）
                if (i + 1 >= args.length) { // 检查是否有对应的参数值
                    throw new IllegalArgumentException("参数 " + args[i] + " 缺少值"); // 抛出异常，参数缺少值
                }
                
                switch (args[i]) { // 根据参数名进行分支处理
                    case "-id": // 账户ID参数
                        id = args[i + 1]; // 获取参数值并赋给id变量
                        break; // 跳出switch语句
                    case "-name": // 姓名参数
                        name = args[i + 1]; // 获取参数值并赋给name变量
                        break; // 跳出switch语句
                    case "-balance": // 余额参数
                        balance = Double.parseDouble(args[i + 1]); // 解析字符串为double类型并赋给balance变量
                        break; // 跳出switch语句
                    default: // 未知参数
                        throw new IllegalArgumentException("未知参数: " + args[i]); // 抛出异常，未知参数
                }
            }
            
            if (id == null || name == null) { // 检查必需参数是否都已提供
                throw new IllegalArgumentException("缺少必需参数。用法: create -id <账户ID> -name <姓名> -balance <初始余额>"); // 抛出异常，缺少必需参数
            }
            
            if (accounts.containsKey(id)) { // 检查账户ID是否已存在
                throw new IllegalArgumentException("账户ID " + id + " 已存在"); // 抛出异常，账户ID重复
            }
            
            Account account = new Account(id, name, balance); // 创建新的Account对象
            accounts.put(id, account); // 将新账户添加到accounts映射中
            
            System.out.printf("账户创建成功: %s (户主: %s, 初始余额: %.2f)%n", id, name, balance); // 打印成功信息
            
        } catch (NumberFormatException e) { // 捕获数字格式异常
            System.err.println("余额格式错误，请输入有效的数字"); // 打印错误信息
        } catch (Exception e) { // 捕获其他异常
            System.err.println(e.getMessage()); // 打印异常信息
        }
    }
    
    /**
     * 处理存款命令
     * deposit -id <账户ID> -amount <存款金额>
     */
    private void handleDepositCommand(String[] args) { // 私有方法，处理存款命令
        try { // 开始try块，捕获可能的异常
            String id = null; // 声明并初始化账户ID变量
            double amount = 0.0; // 声明并初始化存款金额变量
            
            for (int i = 1; i < args.length; i += 2) { // 从索引1开始遍历参数数组，每次增加2
                if (i + 1 >= args.length) { // 检查是否有对应的参数值
                    throw new IllegalArgumentException("参数 " + args[i] + " 缺少值"); // 抛出异常，参数缺少值
                }
                
                switch (args[i]) { // 根据参数名进行分支处理
                    case "-id": // 账户ID参数
                        id = args[i + 1]; // 获取参数值并赋给id变量
                        break; // 跳出switch语句
                    case "-amount": // 存款金额参数
                        amount = Double.parseDouble(args[i + 1]); // 解析字符串为double类型并赋给amount变量
                        break; // 跳出switch语句
                    default: // 未知参数
                        throw new IllegalArgumentException("未知参数: " + args[i]); // 抛出异常，未知参数
                }
            }
            
            if (id == null) { // 检查账户ID是否已提供
                throw new IllegalArgumentException("缺少必需参数。用法: deposit -id <账户ID> -amount <存款金额>"); // 抛出异常，缺少必需参数
            }
            
            Account account = accounts.get(id); // 从accounts映射中获取指定ID的账户
            if (account == null) { // 检查账户是否存在
                throw new IllegalArgumentException("账户 " + id + " 不存在"); // 抛出异常，账户不存在
            }
            
            account.deposit(amount); // 调用账户的存款方法
            System.out.printf("存款成功，账户 %s 当前余额: %.2f%n", id, account.getBalance()); // 打印成功信息和当前余额
            
        } catch (NumberFormatException e) { // 捕获数字格式异常
            System.err.println("金额格式错误，请输入有效的数字"); // 打印错误信息
        } catch (Exception e) { // 捕获其他异常
            System.err.println(e.getMessage()); // 打印异常信息
        }
    }
    
    /**
     * 处理取款命令
     * withdraw -id <账户ID> -amount <取款金额>
     */
    private void handleWithdrawCommand(String[] args) { // 私有方法，处理取款命令
        try { // 开始try块，捕获可能的异常
            String id = null; // 声明并初始化账户ID变量
            double amount = 0.0; // 声明并初始化取款金额变量
            
            for (int i = 1; i < args.length; i += 2) { // 从索引1开始遍历参数数组，每次增加2
                if (i + 1 >= args.length) { // 检查是否有对应的参数值
                    throw new IllegalArgumentException("参数 " + args[i] + " 缺少值"); // 抛出异常，参数缺少值
                }
                
                switch (args[i]) { // 根据参数名进行分支处理
                    case "-id": // 账户ID参数
                        id = args[i + 1]; // 获取参数值并赋给id变量
                        break; // 跳出switch语句
                    case "-amount": // 取款金额参数
                        amount = Double.parseDouble(args[i + 1]); // 解析字符串为double类型并赋给amount变量
                        break; // 跳出switch语句
                    default: // 未知参数
                        throw new IllegalArgumentException("未知参数: " + args[i]); // 抛出异常，未知参数
                }
            }
            
            if (id == null) { // 检查账户ID是否已提供
                throw new IllegalArgumentException("缺少必需参数。用法: withdraw -id <账户ID> -amount <取款金额>"); // 抛出异常，缺少必需参数
            }
            
            Account account = accounts.get(id); // 从accounts映射中获取指定ID的账户
            if (account == null) { // 检查账户是否存在
                throw new IllegalArgumentException("账户 " + id + " 不存在"); // 抛出异常，账户不存在
            }
            
            account.withdraw(amount); // 调用账户的取款方法，可能抛出InsufficientBalanceException
            System.out.printf("取款成功，账户 %s 当前余额: %.2f%n", id, account.getBalance()); // 打印成功信息和当前余额
            
        } catch (NumberFormatException e) { // 捕获数字格式异常
            System.err.println("金额格式错误，请输入有效的数字"); // 打印错误信息
        } catch (Exception e) { // 捕获其他异常（包括InsufficientBalanceException）
            System.err.println(e.getMessage()); // 打印异常信息
        }
    }
    
    /**
     * 处理转账命令
     * transfer -from <转出账户ID> -to <转入账户ID> -amount <转账金额>
     */
    private void handleTransferCommand(String[] args) { // 私有方法，处理转账命令
        try { // 开始try块，捕获可能的异常
            String fromId = null, toId = null; // 声明并初始化转出和转入账户ID变量
            double amount = 0.0; // 声明并初始化转账金额变量
            
            for (int i = 1; i < args.length; i += 2) { // 从索引1开始遍历参数数组，每次增加2
                if (i + 1 >= args.length) { // 检查是否有对应的参数值
                    throw new IllegalArgumentException("参数 " + args[i] + " 缺少值"); // 抛出异常，参数缺少值
                }
                
                switch (args[i]) { // 根据参数名进行分支处理
                    case "-from": // 转出账户ID参数
                        fromId = args[i + 1]; // 获取参数值并赋给fromId变量
                        break; // 跳出switch语句
                    case "-to": // 转入账户ID参数
                        toId = args[i + 1]; // 获取参数值并赋给toId变量
                        break; // 跳出switch语句
                    case "-amount": // 转账金额参数
                        amount = Double.parseDouble(args[i + 1]); // 解析字符串为double类型并赋给amount变量
                        break; // 跳出switch语句
                    default: // 未知参数
                        throw new IllegalArgumentException("未知参数: " + args[i]); // 抛出异常，未知参数
                }
            }
            
            if (fromId == null || toId == null) { // 检查必需参数是否都已提供
                throw new IllegalArgumentException("缺少必需参数。用法: transfer -from <转出账户ID> -to <转入账户ID> -amount <转账金额>"); // 抛出异常，缺少必需参数
            }
            
            Account fromAccount = accounts.get(fromId); // 从accounts映射中获取转出账户
            Account toAccount = accounts.get(toId); // 从accounts映射中获取转入账户
            
            if (fromAccount == null) { // 检查转出账户是否存在
                throw new IllegalArgumentException("转出账户 " + fromId + " 不存在"); // 抛出异常，转出账户不存在
            }
            if (toAccount == null) { // 检查转入账户是否存在
                throw new IllegalArgumentException("转入账户 " + toId + " 不存在"); // 抛出异常，转入账户不存在
            }
            
            fromAccount.transfer(toAccount, amount); // 调用转出账户的转账方法
            System.out.printf("转账成功，从 %s 转账 %.2f 到 %s%n", fromId, amount, toId); // 打印转账成功信息
            System.out.printf("账户 %s 余额: %.2f，账户 %s 余额: %.2f%n", // 打印两个账户的当前余额
                fromId, fromAccount.getBalance(), toId, toAccount.getBalance()); // 获取并显示账户余额
            
        } catch (NumberFormatException e) { // 捕获数字格式异常
            System.err.println("金额格式错误，请输入有效的数字"); // 打印错误信息
        } catch (Exception e) { // 捕获其他异常（包括InsufficientBalanceException）
            System.err.println(e.getMessage()); // 打印异常信息
        }
    }
    
    /**
     * 处理查询余额命令
     * balance -id <账户ID>
     */
    private void handleBalanceCommand(String[] args) { // 私有方法，处理查询余额命令
        try { // 开始try块，捕获可能的异常
            String id = null; // 声明并初始化账户ID变量
            
            for (int i = 1; i < args.length; i += 2) { // 从索引1开始遍历参数数组，每次增加2
                if (i + 1 >= args.length) { // 检查是否有对应的参数值
                    throw new IllegalArgumentException("参数 " + args[i] + " 缺少值"); // 抛出异常，参数缺少值
                }
                
                if ("-id".equals(args[i])) { // 检查参数是否为-id
                    id = args[i + 1]; // 获取参数值并赋给id变量
                } else { // 未知参数
                    throw new IllegalArgumentException("未知参数: " + args[i]); // 抛出异常，未知参数
                }
            }
            
            if (id == null) { // 检查账户ID是否已提供
                throw new IllegalArgumentException("缺少必需参数。用法: balance -id <账户ID>"); // 抛出异常，缺少必需参数
            }
            
            Account account = accounts.get(id); // 从accounts映射中获取指定ID的账户
            if (account == null) { // 检查账户是否存在
                throw new IllegalArgumentException("账户 " + id + " 不存在"); // 抛出异常，账户不存在
            }
            
            System.out.printf("余额: %.2f%n", account.getBalance()); // 打印账户余额
            
        } catch (Exception e) { // 捕获所有异常
            System.err.println(e.getMessage()); // 打印异常信息
        }
    }
    
    /**
     * 显示帮助信息
     */
    private void showHelp() { // 私有方法，显示系统帮助信息
        System.out.println("=== 银行账户管理系统 - 命令帮助 ==="); // 打印帮助标题
        System.out.println(); // 打印空行，增加可读性
        System.out.println("可用命令:"); // 打印可用命令标题
        System.out.println("  create -id <账户ID> -name <姓名> -balance <初始余额>"); // 打印创建账户命令格式
        System.out.println("    创建新账户"); // 打印创建账户命令说明
        System.out.println(); // 打印空行，分隔命令
        System.out.println("  deposit -id <账户ID> -amount <存款金额>"); // 打印存款命令格式
        System.out.println("    向指定账户存款"); // 打印存款命令说明
        System.out.println(); // 打印空行，分隔命令
        System.out.println("  withdraw -id <账户ID> -amount <取款金额>"); // 打印取款命令格式
        System.out.println("    从指定账户取款"); // 打印取款命令说明
        System.out.println(); // 打印空行，分隔命令
        System.out.println("  transfer -from <转出账户ID> -to <转入账户ID> -amount <转账金额>"); // 打印转账命令格式
        System.out.println("    在账户间转账"); // 打印转账命令说明
        System.out.println(); // 打印空行，分隔命令
        System.out.println("  balance -id <账户ID>"); // 打印查询余额命令格式
        System.out.println("    查询账户余额"); // 打印查询余额命令说明
        System.out.println(); // 打印空行，分隔命令
        System.out.println("  help"); // 打印帮助命令格式
        System.out.println("    显示此帮助信息"); // 打印帮助命令说明
        System.out.println(); // 打印空行，分隔命令
        System.out.println("  exit"); // 打印退出命令格式
        System.out.println("    退出系统"); // 打印退出命令说明
        System.out.println(); // 打印空行，分隔命令和示例
        System.out.println("示例:"); // 打印示例标题
        System.out.println("  create -id A001 -name Alice -balance 1000"); // 打印创建账户示例
        System.out.println("  deposit -id A001 -amount 500"); // 打印存款示例
        System.out.println("  withdraw -id A001 -amount 200"); // 打印取款示例
        System.out.println("  transfer -from A001 -to B002 -amount 300"); // 打印转账示例
        System.out.println("  balance -id A001"); // 打印查询余额示例
    }
} // 类定义结束